#include "Precomp.h"
#include "SaveData.h"
#include "mapformat.pb.h"
#include <exception>

namespace SGF
{
#ifdef _DEBUG
#	define TYPE_CHECK(expected) if(type!=expected) throw InvalidTypeException("Invalid Type: " #expected " expected");
#else
#	define TYPE_CHECK
#endif

	SaveValue::SaveValue(mapformat::Data* innerVal)
	:innerVal(innerVal)
	{
		type=(ValueType)(innerVal->datatype());
	}

	SaveValue::SaveValue(const SaveValue& other)
	{
		innerVal=other.innerVal;
		type=(ValueType)(innerVal->datatype());
	}

	SaveValue& SaveValue::operator=(int val)
	{
		type=Int;
		innerVal->set_datatype(mapformat::Data::INT);
		innerVal->set_ivalue(val);
		return *this;
	}

	SaveValue& SaveValue::operator=(float val)
	{
		type=Float;
		innerVal->set_datatype(mapformat::Data::FLOAT);
		innerVal->set_fvalue(val);
		return *this;
	}

	SaveValue& SaveValue::operator=(const char* val)
	{
		type=String;
		innerVal->set_datatype(mapformat::Data::STRING);
		innerVal->set_svalue(val);
		return *this;
	}

	SaveValue& SaveValue::operator=(bool val)
	{
		type=Bool;
		innerVal->set_datatype(mapformat::Data::BOOL);
		innerVal->set_bvalue(val);
		return *this;
	}

	SaveValue& SaveValue::operator=(const Ogre::Vector3& val)
	{
		type=Vector;
		innerVal->set_datatype(mapformat::Data::VECTOR);
		mapformat::Vector* vector=innerVal->mutable_vvalue();
		vector->set_x(val.x);
		vector->set_y(val.y);
		vector->set_z(val.z);
		return *this;
	}

	SaveValue& SaveValue::operator =(const SaveValue& other)
	{
		type=other.type;
		*innerVal=*(other.innerVal);
		return *this;
	}

	SaveValue::operator int() const
	{
		if(type==Unknown) return 0;
		TYPE_CHECK(Int);
		return innerVal->ivalue();
	}

	SaveValue::operator float() const
	{
		if(type==Unknown) return 0.f;
		TYPE_CHECK(Float);
		return innerVal->fvalue();
	}

	SaveValue::operator bool() const
	{
		if(type==Unknown) return false;
		TYPE_CHECK(Bool);
		return innerVal->bvalue();
	}

	SaveValue::operator const char*() const
	{
		if(type==Unknown) return NULL;
		TYPE_CHECK(Bool);
		return innerVal->svalue().c_str();
	}

	SaveValue::operator Ogre::Vector3() const
	{
		TYPE_CHECK(Vector);
		const mapformat::Vector& vector=innerVal->vvalue();
		return Ogre::Vector3(vector.x(),vector.y(),vector.z());
	}

	SaveData::SaveData(mapformat::Entity* innerData)
	:innerData(innerData)
	{
		google::protobuf::RepeatedPtrField<mapformat::Data>* userdata=innerData->mutable_userdata();
		foreach(mapformat::Data& value,*userdata)
		{
			dataMap.insert(std::make_pair(value.key(),&value));
		}
	}

	SaveValue& SaveData::operator[](const char* key)
	{
		std::map<std::string,SaveValue>::iterator it=dataMap.find(key);
		if(it==dataMap.end())//not found
		{
			mapformat::Data* newUserData=innerData->add_userdata();
			newUserData->set_key(key);
			return dataMap.insert(std::make_pair(key,newUserData)).first->second;
		}
		return it->second;
	}

	const SaveValue& SaveData::operator[](const char* key) const
	{
		std::map<std::string,SaveValue>::const_iterator it=dataMap.find(key);
		if(it==dataMap.end())//not found
		{
			mapformat::Data* newUserData=innerData->add_userdata();
			newUserData->set_key(key);
			return dataMap.insert(std::make_pair(key,newUserData)).first->second;
		}
		return it->second;
	}
}